package ar.com.cubika.trainees.bean.transportes.actividades;

import java.util.Date;

import ar.com.cubika.trainees.bean.transportes.Chofer;
import ar.com.cubika.trainees.bean.transportes.Ruta;
import ar.com.cubika.trainees.bean.transportes.vehiculos.Vehiculo;
import ar.com.cubika.trainees.date.DateUtils;
import ar.com.cubika.trainees.date.RangoDeFechas;
import ar.com.cubika.trainees.exceptions.BusinessException;

/**
 * Representa cada viaje que debe llevar a cabo la empresa de transportes
 * 
 * @author Carlos
 */
public class Viaje implements Actividad {
    private Ruta ruta;
    private long carga;
    private double tiempoMaximo;
    private Date fechaPartida;
    private Vehiculo vehiculo;
    private String chofer;
    
    /**
     * Constructor comodo 
     */
    public Viaje(Ruta ruta, long carga, double tiempoMaximo) {
    	this();
        this.ruta = ruta;
        this.carga = carga;
        this.tiempoMaximo = tiempoMaximo;
    }
    
    /**
     * Para Hibernate
     */
    public Viaje() {
	}


    /**
     * Asigna el viaje a un vehiculo
     * @param veh el vehiculo al que se asigna el viaje
     * @see Vehiculo#addViaje(Viaje)
     * @throws BusinessException 
     * 		si el viaje ya tenia un vehiculo asignado
     * @throws BusinessException
     * 		si el vehiculo no puede hacer el viaje
     */
    public synchronized void asignar(Vehiculo veh) throws BusinessException {
        synchronized (veh) {
            if (this.isAsignado()) {
                throw new BusinessException(
                        "Viaje " + this + "ya tiene un vehiculo asignado");
            } else if (!veh.puedeHacer(this)) {
                throw new BusinessException(
                        "Vehiculo " + veh + " no puede hacer el viaje " + this);
            }
            this.vehiculo = veh;
            veh.addViaje(this);
        }
    }
    
    public String getChofer() {
		return chofer;
	}

	public void setChofer(String chofer) {
		this.chofer = chofer;
	}

	/**
     * Desasigna el viaje, o sea le saca el vehiculo que lo tenia asignado.
     * @see Vehiculo#removeViaje(Viaje)
     * @throws BusinessException
     * 		si el viaje no tiene vehiculo asignado
     */
    public synchronized void desasignar() {
    	this.checkViajeAsignado();
    	this.vehiculo.removeViaje(this);
    	this.vehiculo = null;
    }
    
    
	/**
     * La carga que debe llevar el viaje, en kilos
     */
    public long getCarga() {
        return carga;
    }
    
    /**
     * La ruta que va a seguir el viaje 
     */
    public Ruta getRuta() {
        return ruta;
    }
    
    /**
     * El vehiculo que tiene asignado el viaje
     */
    public Vehiculo getVehiculo() {
    	return this.vehiculo;
    }
    
    /* (non-Javadoc)
	 * @see ar.com.cubika.trainees.bean.transportes.actividades.Actividad#getDescripcion()
	 */
	public String getDescripcion() {
		return "Viaje: " + this.getRuta();
	}

	/**
     * Indica si el viaje esta asignado a un vehiculo
     * @return un boolean
     */
	public synchronized boolean isAsignado() {
		return this.vehiculo != null;
	}
    
    
    /**
     * El limite de tiempo para el viaje, en horas  
     */
    public double getTiempoMaximo() {
        return tiempoMaximo;
    }
    
    /**
     * El tiempo que se estima para este viaje, en horas. 
     * Depende del vehiculo asignado.
     * @throws BusinessException
     * 			si el viaje no tiene vehiculo asignado
     */
    public double getTiempoEstimado() {
    	this.checkViajeAsignado();
    	return this.vehiculo.getTiempo(this);
    }
    

    /**
     * El origen del viaje 
     */
    public String getOrigen() {
        return ruta.getOrigen();
    }

    /**
     * El destino del viaje
     */
    public String getDestino() {
        return ruta.getDestino();
    }
    
    /**
     * La cantidad total de km del viaje
     */
    public long getKm() {
        return ruta.getKm();
    }
    
    /**
     * La cantidad de km de camino en buen estado
     */
    public long getKmBuenCamino() {
        return ruta.getKmBuenCamino();
    }
    
    /**
     * La cantidad de km de camino en buen estado
     */
    public long getKmMalCamino() {
        return ruta.getKmMalCamino();
    }

    
    /**
     * La fecha en la que empieza el viaje
     */
    public Date getFechaPartida() {
		return fechaPartida;
	}

	/* (non-Javadoc)
	 * @see ar.com.cubika.trainees.bean.transportes.actividades.Actividad#incluyeFecha(java.util.Date)
	 */
	public boolean incluyeFecha(Date fecha) {
		Date fechaHasta = DateUtils.addDays(
				this.getFechaPartida(), this.getDiasEstimados());
		return new RangoDeFechas(
				this.getFechaPartida(), fechaHasta).incluye(fecha);
	}

	/**
	 * La cantidad de dias enteros incluidos en la duracion estimada 
	 * del viaje.
	 */
	protected long getDiasEstimados() {
		return Math.round(Math.floor((this.getTiempoEstimado() + 1E-8) / 24));
	}


    /**
     * Chequea que el viaje esta asignado, en ese caso lanza una excepcion.
     * @throws BusinessException
     * 			si el viaje no tiene vehiculo asignado
     */
	protected void checkViajeAsignado() {
		if (!this.isAsignado()) {
    		throw new BusinessException("Viaje " + this + 
    				" sin vehiculo asignado");
    	}
	}

	public void setCarga(long carga) {
        this.carga = carga;
    }

    public void setRuta(Ruta ruta) {
        this.ruta = ruta;
    }

    public void setTiempoMaximo(double tiempoMaximo) {
        this.tiempoMaximo = tiempoMaximo;
    }

    public void setFechaPartida(Date fechaPartida) {
		this.fechaPartida = fechaPartida;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return this.getRuta() + " llevando " + this.getCarga();
	}
    
    
}
